package com.onpositive.datamap.core.impl;

import java.io.Serializable;

import com.onpositive.data.IPropertyConstants;
import com.onpositive.data.IPropertyMetadata;
import com.onpositive.data.diskstorage.AbstractValueAccessor;
import com.onpositive.data.diskstorage.StoredMetadata;
import com.onpositive.data.units.DateWithAccuracy;
import com.onpositive.datamap.IDataPropertyValue;
import com.onpositive.datamap.core.IDataObject;
import com.onpositive.datamap.core.IDataProperty;
import com.onpositive.datamap.values.impl.DateRange;
import com.onpositive.datamap.values.impl.ValueSequence;
import com.onpositive.semantic.model.api.changes.ObjectChangeManager;
import com.onpositive.semantic.model.api.command.CompositeCommand;
import com.onpositive.semantic.model.api.command.DefaultCommandFactory;
import com.onpositive.semantic.model.api.command.ICommand;
import com.onpositive.semantic.model.api.command.ICommandExecutor;
import com.onpositive.semantic.model.api.command.ICommandFactory;
import com.onpositive.semantic.model.api.command.IHasCommandExecutor;
import com.onpositive.semantic.model.api.command.SimpleOneArgCommand;
import com.onpositive.semantic.model.api.meta.BaseMeta;
import com.onpositive.semantic.model.api.meta.IMeta;
import com.onpositive.semantic.model.api.property.IHasPropertyProvider;
import com.onpositive.semantic.model.api.property.IProperty;
import com.onpositive.semantic.model.api.property.IPropertyProvider;
import com.onpositive.semantic.model.api.property.PropertyAccess;

public abstract class AbstractDataProperty implements IProperty, Serializable,
		IDataProperty, IHasPropertyProvider, ICommandExecutor,
		IHasCommandExecutor {

	private static final String PROPERTY_DESCRIPTION = "property_description";
	private static final String VISUAL_PROPERTY_GROUP = "property_group";
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	public StoredMetadata meta;
	public AbstractValueAccessor accessor;
	protected BaseMeta metaP = new BaseMeta();

	@Override
	public final Object getValue(Object obj) {
		if (!(obj instanceof IDataObject)){
			return null;
		}
		return accessor.getValue((IDataObject) obj, this);
	}

	@Override
	public final IDataPropertyValue getValue(IDataObject object) {
		return accessor.getValue(object, this);
	}

	@Override
	public int getPriority() {
		Object metaPropertyValue = meta.getMetaPropertyValue("priority");
		if (metaPropertyValue instanceof String) {
			metaPropertyValue = Integer.parseInt((String) metaPropertyValue);
		}
		if (metaPropertyValue instanceof Number) {
			int intValue = ((Number) metaPropertyValue).intValue();			
			return intValue;
		}
		return 0;
	}
	
	public void setPriority(int p){
		meta.setVlaue("priority", p);
	}

	public String basicPropertyGroup() {
		String metaPropertyValue = (String) meta
				.getMetaPropertyValue(IPropertyConstants.CHAR_GROUP_LABEL);
		if (metaPropertyValue == null || metaPropertyValue.length() == 0) {
			return getBasicGroup(meta);
		}
		return metaPropertyValue;
	}

	public static String getBasicGroup(IPropertyMetadata meta2) {
		Object value3 = meta2
				.getMetaPropertyValue(IPropertyConstants.CHAR_UNIT_LABEL);
		if (value3 != null) {
			return value3.toString();
		}
		Object value = meta2.getMetaPropertyValue("parser-id");
		if (value != null) {
			return (String) value;
		}
		return "";
	}

	@Override
	public IMeta getMeta() {
		return metaP;
	}

	@Override
	public String id() {
		return meta.id();
	}
	
	
	public String getGroup(){
		return group();		
	}
	
	public String getBasicGroup(){
		return basicPropertyGroup();
	}
	
	public void setGroup(String str){		
		meta.setVlaue(VISUAL_PROPERTY_GROUP, str);
	}
	
	public String getName(){
		return (String) meta.getMetaPropertyValue(IPropertyConstants.CHAR_PROPERTY_NAME_LABEL);
	}
	
	public void setName(String name){
		meta.setVlaue(IPropertyConstants.CHAR_PROPERTY_NAME_LABEL, name);
	}
	
	public String getDescription(){
		return description();
	}
	
	public void setDescription(String desString){
		meta.setVlaue(PROPERTY_DESCRIPTION,desString);
	}
	
	

	@Override
	public String name() {
		return (String) meta
				.getMetaPropertyValue(IPropertyConstants.CHAR_PROPERTY_NAME_LABEL);
	}

	public IPropertyProvider getPropertyProvider() {
		return PropertyAccess.getPropertyProvider(getClass());
	}
	
	public AbstractDataProperty(IPropertyMetadata meta,
			AbstractValueAccessor accessor) {
		super();
		this.meta = (StoredMetadata) meta;
		this.accessor = accessor;
		metaP.registerService(ICommandFactory.class,
				new DefaultCommandFactory());
		metaP.registerService(ICommandExecutor.class, this);
		metaP.registerService(IHasCommandExecutor.class, this);
	}

	@Override
	public String group() {
		String metaPropertyValue = (String) meta.getMetaPropertyValue(VISUAL_PROPERTY_GROUP);
		if (metaPropertyValue == null || metaPropertyValue.length() == 0) {
			return "Other";
		}
		return metaPropertyValue;
	}

	public PropertyGroup getPropertyGroup() {
		return new PropertyGroup(group());
	}

	@Override
	public String description() {
		return (String) meta
				.getMetaPropertyValue(PROPERTY_DESCRIPTION);
	}

	@Override
	public String getId() {
		return id();
	}

	public Class<?> getType() {
		if (meta != null)
			return meta.type();
		return null;
	}

	public IDataPropertyValue convert(Object value) {
		if (!(value instanceof IDataPropertyValue)) {
			if (value instanceof String) {
				if (((String) value).length() > 0) {
					return new ValueSequence(this, null,
							((String) value).split("_#_"));
				}
				return null;
			}
		}
		return (IDataPropertyValue) value;
	}
	
	
	protected void updateMeta(){
		accessor.updateMeta(meta);
	}

	@Override
	public String toString() {
		return name();
	}

	@Override
	public void execute(ICommand cmd) {
		if (cmd instanceof CompositeCommand) {
			CompositeCommand m=(CompositeCommand) cmd;
			for (ICommand q:m){
				execute(q);
			}
		}
		if (cmd instanceof SimpleOneArgCommand) {
			SimpleOneArgCommand m = (SimpleOneArgCommand) cmd;
			IDataObject o = (IDataObject) m.getTarget();
			Object value = m.getValue();
			if (value instanceof String) {
				
				String[] vls=((String) value).split(",");
				
				StringBuilder bld=new StringBuilder();
				int a=0;
				for (String v:vls){
					bld.append(v.trim());
					if (a!=vls.length-1){
					bld.append("_#_");
					}
					a++;
				}
				value=bld.toString();
				value = adaptFilterValue((String) value);
			}
			if (value instanceof DateWithAccuracy) {
				value = new DateRange(this, null, (DateWithAccuracy) value);
			}
			accessor.setValue(o, this, value);
			ObjectChangeManager.markChanged(o);
		}
	}

	@Override
	public ICommandExecutor getCommandExecutor() {
		return this;
	}

	@Override
	public ICommandFactory getCommandFactory() {
		return DefaultCommandFactory.INSTANCE;
	}

	public boolean isCollection() {
		return false;
	}
}